package com.gmstu.springorm.framework;


import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author John.zhang
 * @version Id: QueryRuleSqlBuilder, v 1.0 2020/9/1 18:55 ZhiYong Exp $
 */
public class QueryRuleSqlBuilder {

    private int CURR_INDEX = 0;

    private List<String> properties;

    private List<Object> values;

    private List<Order> orders;

    private String whereSql = "";

    private String orderSql = "";

    private Object[] valueArr = new Object[]{};

    private Map<Object, Object> valueMap = new HashMap<Object, Object>();

    public String getWhereSql() {
        return whereSql;
    }

    public String getOrderSql() {
        return orderSql;
    }

    public Object[] getValueArr() {
        return valueArr;
    }

    public Object [] getValues() {
        return this.valueArr;
    }

    public Map<Object, Object> getValueMap() {
        return valueMap;
    }

    public QueryRuleSqlBuilder(QueryRule queryRule) {
        CURR_INDEX = 0;
        properties = new ArrayList<String>();
        values = new ArrayList<Object>();
        orders = new ArrayList<Order>();
        for (QueryRule.Rule rule : queryRule.getRuleList()) {
            switch (rule.getType()) {
                case QueryRule.LIKE:
                    processLike(rule);
                    break;
                case QueryRule.ASC_ORDER:
                case QueryRule.DESC_ORDER:
                    processOrder(rule);
                    break;
                default:
                    throw new IllegalArgumentException("type" + rule.getType() + "not supported.");
            }
        }

        appendWhereSql();

        appendOrderSql();

        appendValues();

    }


    private void appendValues() {
        Object[] val = new Object[values.size()];
        for (int i = 0; i < values.size(); i++) {
            val[i] = values.get(i);
            valueMap.put(i, values.get(1));
        }
        this.valueArr = val;
    }

    private void appendOrderSql() {
        StringBuffer orderSql = new StringBuffer();
        for (int i = 0; i < orders.size(); i++) {
            if (i > 0 && i < orders.size()) {
                orderSql.append(",");
            }
            orderSql.append(orders.get(i).toString());
            this.orderSql = orderSql.toString();
        }


    }

    private void appendWhereSql() {
        StringBuffer whereSql = new StringBuffer();
        for (String property : properties) {
            whereSql.append(property);
        }
        this.whereSql = whereSql.toString();
    }

    private void processLike(QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        Object obj = rule.getValues()[0];
        if (obj != null) {
            String value = obj.toString();
            if (!StringUtils.isEmpty(value)) {
                value = value.replace("*", "%");
                obj = value;
            }
        }
        add(rule.getAndOr(), rule.getPropertyName(), "like", "%" + obj + "%");
    }

    private void processOrder(QueryRule.Rule rule) {
        switch (rule.getType()) {
            case QueryRule.ASC_ORDER:
                if (StringUtils.isNotEmpty(rule.getPropertyName())) {
                    orders.add(Order.asc(rule.getPropertyName()));
                }
                break;
            case QueryRule.DESC_ORDER:
                if (StringUtils.isNotEmpty(rule.getPropertyName())) {
                    orders.add(Order.desc(rule.getPropertyName()));
                }
                break;
            default:
                break;
        }
    }

    private void add(int andOr, String key, String split, Object value) {
        add(andOr, key, split, "", value, "");
    }

    private void add(int andOr, String key, String split, String prefix, Object value, String suffix) {
        String andOrStr = (0 == andOr ? "" : (QueryRule.AND == andOr ? " and" : " or "));
        properties.add(CURR_INDEX, andOrStr + key + " " + split + prefix + (null != value ? " ? " : " ") + suffix);
        if (null != value) {
            values.add(CURR_INDEX, value);
            CURR_INDEX++;
        }
    }
}
